import os
import logging
import bincopy
import binascii

class ParseFile:

    def get_Address_Lenth(self, filepath):
        """
        获取文件的所有地址段信息
            
        Args:
            filepath (str): 文件路径，支持.bin/.BIN/.hex/.s19格式
            
        Returns:
            list: 包含多个地址段的列表，每个元素为(start_address, segment_size)元组
                    .bin/.BIN文件返回单个元素的列表
                    .hex/.s19文件返回所有段的列表
        """
        segments, file_type = self.parse_file(filepath)
        
        # 处理二进制文件(.bin/.BIN)
        if file_type in ('.bin', '.BIN'):
            return [(self.startaddress, self.size)]
        
        # 处理HEX文件 - 返回所有段
        address_list = []
        size_list = []
        for seg in segments:
            start_address = seg.minimum_address
            segment_size = seg.maximum_address - seg.minimum_address
            address_list.append(start_address)
            size_list.append(segment_size)
            logging.info(f"Segment info - Start: 0x{start_address:X}, Size: 0x{segment_size:X}")
            
        return address_list, size_list

    def parse_file(self, file_path):
        """
        解析二进制/HEX/S19文件，提取地址段和数据

        Args:
            file_path (str): 待解析的文件路径（支持.bin/.hex/.s19格式）

        Returns:
            list: 二进制文件句柄的段列表（每个段包含起始地址、长度和数据）

        Raises:
            Exception: 文件解析失败时抛出异常
        """
        file_type = os.path.splitext(file_path)[-1].lower()
        binfile_handle = bincopy.BinFile()
        
        try:
            with open(file_path, 'r') as fin:
                if file_type == '.hex':
                    # 读取HEX文件所有段
                    binfile_handle.add_ihex(fin.read())
                    
                    # 获取所有独立地址段
                    segments = []
                    for seg in binfile_handle.segments:
                        start = seg.minimum_address
                        length = seg.maximum_address - seg.minimum_address
                        segments.append({
                            'startAddress': start,
                            'length': length,
                            'data': seg.data
                        })
                        logging.info(f'Found segment: Start=0x{start:X}, Length=0x{length:X}')

                elif file_type == '.s19':
                    # 解析S19文件记录（支持S1/S2/S3数据记录）
                    s_records = fin.readlines()
                    for line in s_records:
                        line = line.strip()
                        if not line.startswith('S') or len(line) < 10:
                            continue  # 跳过无效行
                        record_type = line[1]
                        # 解析记录长度（LL字段，2位16进制表示数据+地址+校验和的总字节数-1）
                        total_bytes = int(line[2:4], 16) + 1  # 实际总字节数=LL+1
                        # 根据记录类型确定地址长度（S1:2字节, S2:3字节, S3:4字节）
                        address_len = {'1':2, '2':3, '3':4}.get(record_type, 0)
                        if address_len == 0 or (total_bytes < address_len + 3):  # 至少需要地址+数据+校验和
                            continue  # 非数据记录或无效记录
                        # 提取地址和数据
                        address_hex = line[4:4+2*address_len]
                        data_hex = line[4+2*address_len:-2]  # 去除校验和（最后2位）
                        try:
                            address = int(address_hex, 16)
                            data = bytes.fromhex(data_hex)
                        except ValueError:
                            logging.warning(f'S19无效记录: {line}')
                            continue
                        # 添加数据到二进制文件句柄
                        binfile_handle.add_binary(data, address=address)
                    # 提取S19文件的地址段信息
                    segments = []
                    for seg in binfile_handle.segments:
                        start = seg.minimum_address
                        length = seg.maximum_address - seg.minimum_address
                        segments.append({
                            'startAddress': start,
                            'length': length,
                            'data': seg.data
                        })
                        logging.info(f'Found S19 segment: Start=0x{start:X}, Length=0x{length:X}')

                elif file_type == '.bin':
                    binfile_handle.add_binary(fin.read())
                    size = os.path.getsize(file_path)
                    
            return binfile_handle.segments, file_type

        except Exception as e:
            logging.error(f'{file_type}文件解析失败: {str(e)}')
            raise

if __name__ == "__main__":
    file_path = r"E:\project\01_ShangQi_ES39\testscript\ES39\sw\APP_ES39ETC20250523.s19"
    parse = ParseFile()
    segments, file_type = parse.parse_file(file_path)
    for address, size, data in segments:
        print(f"Address: 0x{address:08X}, Size: 0x{size:08X}")